// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using JetBrains.Annotations;
using Microsoft.Data.Entity.ChangeTracking;
using Microsoft.Data.Entity.Infrastructure;
using Microsoft.Data.Entity.Metadata;

namespace Microsoft.Data.Entity.Update
{
    /// <summary>
    ///     <para>  
    ///         The information passed to a database provider to save changes to an entity to the database.
    ///     </para>  
    ///     <para>  
    ///         This interface is typically used by database providers (and other extensions). It is generally  
    ///         not used in application code.  
    ///     </para>  
    /// </summary>
    public interface IUpdateEntry
    {
        /// <summary>
        ///     The type of entity to be saved to the database.
        /// </summary>
        IEntityType EntityType { get; }

        /// <summary>
        ///     The state of the entity to be saved.
        /// </summary>
        EntityState EntityState { get; }

        /// <summary>
        ///     Gets a value indicating if the specified property is modified. If true, the current value assigned
        ///     to the property should be saved to the database.
        /// </summary>
        /// <param name="property"> The property to be checked. </param>
        /// <returns> True if the property is modified, otherwise false. </returns>
        bool IsModified([NotNull] IProperty property);

        /// <summary>
        ///     Gets a value indicating if the specified property should have a value generated by the database.
        /// </summary>
        /// <param name="property"> The property to be checked. </param>
        /// <returns> True if the property should have a value generated by the database, otherwise false. </returns>
        bool IsStoreGenerated([NotNull] IProperty property);

        /// <summary>
        ///     Gets the value assigned to the given property when it was retrieved from the database.
        /// </summary>
        /// <param name="property"> The property to get the original value for. </param>
        /// <returns> The original value for the property. </returns>
        object GetOriginalValue([NotNull] IProperty property);

        /// <summary>
        ///     Gets or sets the value currently assigned to a given property.
        /// </summary>
        /// <param name="propertyBase"> The property to get or set the current value for. </param>
        /// <returns> The current value assigned to the property. </returns>
        object this[[NotNull] IPropertyBase propertyBase] { get; [param: CanBeNull] set; }

        /// <summary>
        ///     Gets an object representing the values assigned to the primary key.
        ///     <see cref="IKeyValue"/> is typically used to test the equivalence of key values. 
        /// </summary>
        /// <param name="originalValue"> A value indicating whether to get the current or original value. </param>
        /// <returns> The values assigned to the primary key. </returns>
        IKeyValue GetPrimaryKeyValue(bool originalValue = false);

        /// <summary>
        ///     Gets an object representing the values assigned to the principal key that a foreign key references.
        ///     <see cref="IKeyValue"/> is typically used to test the equivalence of key values. 
        /// </summary>
        /// <param name="foreignKey"> The foreign key to get the principal key values for. </param>
        /// <param name="originalValue"> A value indicating whether to get the current or original value. </param>
        /// <returns> The values assigned to the key. </returns>
        IKeyValue GetPrincipalKeyValue([NotNull] IForeignKey foreignKey, bool originalValue = false);

        /// <summary>
        ///     Gets an object representing the values assigned to a foreign key.
        ///     <see cref="IKeyValue"/> is typically used to test the equivalence of key values. 
        /// </summary>
        /// <param name="foreignKey"> The foreign key to get values for. </param>
        /// <param name="originalValue"> A value indicating whether to get the current or original value. </param>
        /// <returns> The values assigned to the key. </returns>
        IKeyValue GetDependentKeyValue([NotNull] IForeignKey foreignKey, bool originalValue = false);

        /// <summary>
        ///     Gets an <see cref="EntityEntry"/> for the entity being saved. <see cref="EntityEntry"/> is an API optimized for
        ///     application developers and <see cref="IUpdateEntry"/> is optimized for database providers, but there may be instances
        ///     where a database provider wants to access information from <see cref="EntityEntry"/>.
        /// </summary>
        /// <returns> An <see cref="EntityEntry"/> for this entity. </returns>
        EntityEntry ToEntityEntry();
    }
}
